// @Author EthanScriptOn
// @Desc
package config_context

import (
	"errors"
	"gitee.com/fatzeng/srf_switch_basic_components/context"
	"gitee.com/fatzeng/srf_switch_basic_components/custom_exp"
	"gitee.com/fatzeng/srf_switch_basic_components/node"
	"gitee.com/fatzeng/srf_switch_basic_components/resource"
	"gitee.com/fatzeng/srf_switch_config/config_field_cache"
	"gitee.com/fatzeng/srf_switch_config/config_node"
)

type ConfigInitializationContext struct {
	*context.SrfContext
	fieldCache                 []*config_field_cache.ExpansionFieldCache
	resultCoordinator          *config_node.ResultManager
	fileLoadingCache           map[string]struct{}
	currentReferenceProxyStore node.Node
}

func GenerateConfigInitializationContext() *ConfigInitializationContext {
	return &ConfigInitializationContext{
		SrfContext:        context.GenerateSrfContext(),
		fieldCache:        make([]*config_field_cache.ExpansionFieldCache, 0),
		resultCoordinator: config_node.GenerateResultManager(),
		fileLoadingCache:  make(map[string]struct{}),
	}
}

func (c *ConfigInitializationContext) AppendCurrentReferenceProxyStore(currentReferenceProxyNode node.Node) (err error) {
	if c.currentReferenceProxyStore == nil {
		c.currentReferenceProxyStore = currentReferenceProxyNode
		return
	}
	return c.currentReferenceProxyStore.SlotNode(node.HEAD, currentReferenceProxyNode)
}

func (c *ConfigInitializationContext) ResetCurrentReferenceProxyStore() {
	c.currentReferenceProxyStore = nil
}

func (c *ConfigInitializationContext) GetCurrentReferenceProxyStore() node.Node {
	return c.currentReferenceProxyStore
}

func (c *ConfigInitializationContext) GetRecentlyCurrentReferenceProxyStore() (node.Node, error) {
	if c.currentReferenceProxyStore == nil {
		return nil, custom_exp.GenerateNoResourceErrorWithErr(errors.New("obtain currentReferenceProxyStore is nil"))
	}
	extremityNode, hasExtremityNode, err := c.currentReferenceProxyStore.GetExtremityNode(node.HEAD)
	if err != nil {
		return nil, err
	}
	if !hasExtremityNode {
		return nil, custom_exp.GenerateNoResourceErrorWithErr(errors.New("obtain currentReferenceProxyStore is nil not hasExtremityNode"))
	}
	return extremityNode, nil
}

func (c *ConfigInitializationContext) SetFieldCache(fieldCache []*config_field_cache.ExpansionFieldCache) {
	c.fieldCache = fieldCache
}

func (c *ConfigInitializationContext) GetFieldCache() []*config_field_cache.ExpansionFieldCache {
	return c.fieldCache
}

func (c *ConfigInitializationContext) GetFileLoadingCache() map[string]struct{} {
	return c.fileLoadingCache
}

func (c *ConfigInitializationContext) SetFileLoadingCache(fileLoadingCache map[string]struct{}) {
	c.fileLoadingCache = fileLoadingCache
}

func (c *ConfigInitializationContext) GetResultCoordinator() *config_node.ResultManager {
	return c.resultCoordinator
}

func (c *ConfigInitializationContext) GetRecentResultList(direction node.OptionDirection) (*config_node.ParseResultPackageNode, error) {
	recentNode, hasNode, err := c.resultCoordinator.GetUnProcessedResult().GetExtremityNode(direction)
	if err != nil {
		return nil, err
	}
	if !hasNode {
		return nil, errors.New("unable to obtain the latest information result list")
	}
	packageNode, ok := recentNode.(*config_node.ParseResultPackageNode)
	if !ok {
		return nil, errors.New("the latest information result list type is not *config_node.ParseResultPackageNode")
	}
	return packageNode, nil
}

func (c *ConfigInitializationContext) SetResultCoordinator(resultCoordinator *config_node.ResultManager) {
	c.resultCoordinator = resultCoordinator
}

func (c *ConfigInitializationContext) LoadConfig(cfg ...interface{}) error {
	return c.SrfContext.GetSettings().OperateResource(&resource.ResourceOptions{
		DoExecute: func(container map[interface{}]interface{}) error {
			configurations, err, hasResult := c.SrfContext.GetSettings().GetResource(InjectedConfigurationCache)
			if err != nil {
				return err
			}
			if !hasResult {
				configurations = make([]interface{}, 0)
			}
			if configurationSlice, ok := configurations.([]interface{}); ok {
				for _, config := range cfg {
					if config == nil {
						continue
					}
					configurationSlice = append(configurationSlice, config)
				}
				_, err, _ = c.SrfContext.GetSettings().AddResource(InjectedConfigurationCache, configurationSlice)
				if err != nil {
					return err
				}
			} else {
				return errors.New("configurations is not a slice")
			}
			return nil
		},
	})
}

func (c *ConfigInitializationContext) GetConfig() ([]interface{}, error) {
	var configs []interface{}
	configCacheValue, err := c.Get(InjectedConfigurationCache)
	if err != nil {
		return configs, err
	}
	interfaceSlice, ok := configCacheValue.([]interface{})
	if !ok {
		return configs, errors.New("configuration data is not a slice")
	}
	return interfaceSlice, nil
}

func (c *ConfigInitializationContext) SetFilePath(filePath string) error {
	return c.Set(SourceLocation, filePath)
}

func (c *ConfigInitializationContext) GetFilePath() (string, error) {
	filePath, err := c.Get(SourceLocation)
	if err != nil {
		return "", err
	}
	filePathStr, ok := filePath.(string)
	if !ok {
		return "", errors.New("unable to obtain file address")
	}
	return filePathStr, nil
}

func (c *ConfigInitializationContext) SetIsOpenEnv(open bool) error {
	return c.Set(EnvLoading, open)
}

func (c *ConfigInitializationContext) IsOpenEnv() bool {
	valueFlag, err := c.Get(EnvLoading)
	if err != nil {
		return false
	}
	openEnv, ok := valueFlag.(bool)
	if !ok {
		return false
	}
	return openEnv
}

func (c *ConfigInitializationContext) SetIsOpenCli(open bool) error {
	return c.Set(CliLoading, open)
}

func (c *ConfigInitializationContext) IsOpenCli() bool {
	valueFlag, err := c.Get(CliLoading)
	if err != nil {
		return false
	}
	openCli, ok := valueFlag.(bool)
	if !ok {
		return false
	}
	return openCli
}
